<?php

namespace app\common\model;

use think\Exception;
use think\facade\Db;
use yiqiniu\extend\db\YqnModel;

/**
 * 基础Model
 * Class BaseModel
 * @package app\common\model
 */
class BaseModel extends YqnModel
{


    /**
     * 获取新的商户编号
     * @param string $table
     * @param string $field
     * @param string $prefix
     * @param int $len
     * @param bool $useDate
     * @return mixed
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getNewCode(string $table, string $field, string $prefix = '', int $len = 6, bool $useDate = false)
    {
        $sql = sprintf("select proc_generate_code('%s', '%s', '%s', %d, %d) as result;", parse_name($table), $field, $prefix, $useDate ? 1 : 0, $len);
        $result = Db::query($sql);

        return current($result)['result'];
    }

    /**
     * 执行存储过程
     * @param       $sql string       要执行sql
     * @param mixed ...$argv 参数
     * @return mixed            返回执行的结果
     * @throws Exception
     */
    public function procedure($sql, ...$argv)
    {
        try {
            $sql = vsprintf($sql, $argv);
            //echo ($sql);
            // 取返回值变量
            $pos = strpos($sql, '@');
            $param = '';
            if ($pos !== false) {
                $param = substr($sql, $pos, strpos($sql, ')') - strlen($sql));
            }
            $this->startTrans();
            if (strpos($this->getConfig('type'), 'mysql') != false) {
                $bret = $this->execute($sql);
                if ($bret != false && !empty($param)) {
                    $bret = $this->query('select ' . $param)[0];
                }
            } else {
                $bret = $this->query($sql)[0];
            }
            $this->commit();
            return $bret;
        } catch (Exception $e) {
            $this->rollback();
            throw $e;
        }
    }

    /**
     * 树添加/修改
     * @param array $data 添加的数据
     * @param string $parentIdField 父ID的字段名
     * @return int  添加成功后ID
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \yiqiniu\extend\exception\ApiException
     */
    protected function treeAddEdit(array $data, string $parentIdField = 'pid'): int
    {


        $id = empty($data["id"]) ? 0 : $data["id"];
        $db = $this->db();
        //判断修改还是删除
        if ($id > 0) {

            //获取修改前的数据
            $oldData = $db->removeOption()->where(["id" => $id])->find();
            if (empty($oldData)) {
                api_exception(API_ERROR, "该信息不存在或已被管理员删除！请返回刷新后重新操作！");
            }
            //如果原始数据ID为新数据的parent_id则不能修改
            if ($oldData["id"] === $data[$parentIdField]) {
                api_exception(API_ERROR, "所属信息不能指定自己！");
            }
            //如果原始数据parent_id不等于新数据的parent_id
            if ($oldData[$parentIdField] !== $data[$parentIdField]) {
                $newParentData = null;
                //如果要修改parent_id且新数据parent_id大于0，则需要depth和tree_path依据新的parent数据产生，否则为0或空
                if ($data[$parentIdField] > 0) {
                    $newParentData = $db->removeOption()->where(["id" => $data[$parentIdField]])->find();
                    if (empty($newParentData)) {
                        api_exception(API_ERROR, "所属信息不存在或已被管理员删除！请返回刷新后重新操作！");
                    }
                    if (in_array($oldData["id"], explode(",", $newParentData["tree_path"]), false)) {
                        api_exception(API_ERROR, "您不能指定该信息的下级作为所属分类！");
                    }
                    $data["depth"] = $newParentData["depth"] + 1;
                    $data["tree_path"] = empty($newParentData["tree_path"]) ? $newParentData["id"] : $newParentData["tree_path"] . "," . $newParentData["id"];
                } else {
                    $data["depth"] = 0;
                    $data["tree_path"] = "";
                }
                $oldParentData = null;
                if ((int)$oldData[$parentIdField] > 0) {
                    $oldParentData = $db->removeOption()->where(["id" => $oldData[$parentIdField]])->find();
                    if (empty($oldParentData)) {
                        api_exception(API_ERROR, "原所属信息不存在或已被管理员删除！请返回刷新后重新操作！");
                    }
                }

                if ((int)$oldData["child"] > 0) {
                    $oldPath = $oldData["tree_path"] ? $oldData["tree_path"] . "," . $oldData["id"] : $oldData["id"];
                    $newPath = $data["tree_path"] ? $data["tree_path"] . "," : "";

                    $db->removeOption()->whereRaw("CONCAT(',',tree_path,',')  like '," . $oldPath . ",%'")->update([
                        "tree_path" => Db::raw("CONCAT('" . $newPath . "',substring(tree_path," . ($oldData["tree_path"] ? (strlen($oldData["tree_path"]) + 2) : 1) . "))"),
                        "depth" => Db::raw("depth+" . ($data["depth"] - $oldData["depth"]))
                    ]);
                }
                if (!empty($newParentData)) {
                    $db->removeOption()->where(["id" => $newParentData["id"]])->inc("child")->update();
                }

                if (!empty($oldParentData)) {
                    $db->removeOption()->where(["id" => $oldParentData["id"]])->dec("child")->update();
                }
            }
            unset($data['id']);
            $db->removeOption()->where("id", $id)->update($data);
        } else {
            if (!empty($data[$parentIdField])) {
                $parentData = $db->removeOption()->where(["id" => $data[$parentIdField]])->find();
                if (empty($parentData)) {
                    api_exception(API_ERROR, "父级信息不存在");
                }
                $db->removeOption()->where(["id" => $parentData["id"]])->inc("child")->update();
                $data["depth"] = $parentData["depth"] + 1;
                if (isset($parentData['tree_path'])) {
                    $parentData['tree_path'] = '';
                }
                $data["tree_path"] = $parentData["tree_path"] ? $parentData["tree_path"] . "," . $parentData["id"] : $parentData["id"];
            }
            unset($data['id']);
            $id = $db->removeOption()->insertGetId($data);
        }
        return $id;
    }
}
